package com.ybear.ybutils.utils.handler

import android.os.Handler
import android.os.Looper
import android.os.Message
import androidx.core.util.Consumer
import com.ybear.ybutils.utils.handler.ThreadPool.Companion.get
import java.lang.ref.WeakReference
import java.util.concurrent.Callable

/**
 * Handler
 */
internal class HandlerImpl : Handler {
    private var mWRCall: WeakReference<com.ybear.ybutils.utils.handler.Callback?>? = null

    constructor(looper: Looper) : super(looper)
    constructor(looper: Looper, call: Callback?) : super(looper, call)
    constructor(call: Callback?) : this(Looper.getMainLooper(), call)
    constructor(looper: Looper, call: com.ybear.ybutils.utils.handler.Callback?) : super(looper, call) {
        mWRCall = WeakReference( call )
    }
    constructor(call: com.ybear.ybutils.utils.handler.Callback?) : this(Looper.getMainLooper(), call)

    private val call: com.ybear.ybutils.utils.handler.Callback? get() = mWRCall?.get()

    override fun dispatchMessage(msg: Message) {
        super.dispatchMessage(msg)
        val call = call
        call?.dispatchMessage(msg)
    }

    fun <T> postAsync(executeCall: Callable<T>, resultCall: Consumer<T>, postResult: Boolean): Boolean {
        return if( postResult ) {
            postExecuteAsync( executeCall, Consumer { data: T -> post { resultCall.accept( data ) } })
        } else postExecuteAsync( executeCall, resultCall )
    }

    fun <T> postAsync(executeCall: Consumer<Consumer<T>>, resultCall: Consumer<T>,
                      postResult: Boolean): Boolean {
        return if( postResult ) {
            postExecuteAsync( executeCall, Consumer { data: T -> post { resultCall.accept( data ) } })
        } else postExecuteAsync( executeCall, resultCall )
    }

    fun <T> postDelayedAsync(executeCall: Callable<T>, resultCall: Consumer<T>,
                             postResult: Boolean, delayMillis: Long): Boolean {
        return postDelayed( { postAsync( executeCall, resultCall, postResult ) }, delayMillis )
    }

    fun <T> postDelayedAsync(executeCall: Consumer<Consumer<T>>, resultCall: Consumer<T>,
                             postResult: Boolean, delayMillis: Long): Boolean {
        return postDelayed( { postAsync( executeCall, resultCall, postResult ) }, delayMillis )
    }

    fun <T> postAsync(executeCall: Callable<T>, resultCall: Consumer<T>,
                      postResult: Boolean, delayMillis: Long): Boolean {
        return postDelayedAsync( executeCall, resultCall, postResult, delayMillis )
    }

    fun <T> postAsync(executeCall: Consumer<Consumer<T>>, resultCall: Consumer<T>,
                      postResult: Boolean, delayMillis: Long): Boolean {
        return postDelayedAsync( executeCall, resultCall, postResult, delayMillis )
    }

    fun <T> postAsync(executeCall: Callable<T>, resultCall: Consumer<T>): Boolean {
        return postAsync( executeCall, resultCall, true )
    }

    fun <T> postAsync(executeCall: Consumer<Consumer<T>>, resultCall: Consumer<T>): Boolean {
        return postAsync( executeCall, resultCall, true )
    }

    fun <T> postDelayedAsync(executeCall: Callable<T>, resultCall: Consumer<T>, 
                             delayMillis: Long): Boolean {
        return postDelayedAsync( executeCall, resultCall, true, delayMillis )
    }

    fun <T> postDelayedAsync(executeCall: Consumer<Consumer<T>>, resultCall: Consumer<T>,
                             delayMillis: Long): Boolean {
        return postDelayedAsync( executeCall, resultCall, true, delayMillis )
    }

    fun <T> postAsync(executeCall: Callable<T>, resultCall: Consumer<T>, 
                      delayMillis: Long): Boolean {
        return postDelayedAsync( executeCall, resultCall, delayMillis )
    }

    fun <T> postAsync(executeCall: Consumer<Consumer<T>>, resultCall: Consumer<T>, 
                      delayMillis: Long): Boolean {
        return postDelayedAsync( executeCall, resultCall, delayMillis )
    }

    fun postAsync(executeCall: Runnable): Boolean {
        return postExecuteAsync( executeCall )
    }

    fun postDelayedAsync(executeCall: Runnable, delayMillis: Long): Boolean {
        return postDelayed( { postExecuteAsync( executeCall ) }, delayMillis )
    }

    fun postAsync(executeCall: Runnable, delayMillis: Long): Boolean {
        return postDelayedAsync( executeCall, delayMillis )
    }

    /**
     * 异步处理Handler( 通过Return返回数据)
     * @param executeCall       处理的异步内容
     * @param resultCall        返回处理的内容
     * @param <T>               数据源
     * @return                  post结果
    </T> */
    private fun <T> postExecuteAsync(executeCall: Callable<T>, resultCall: Consumer<T>): Boolean {
        return postExecuteAsync( Consumer { it.accept( executeCall.call() ) }, resultCall )
    }

    /**
     * 异步处理Handler（通过回调返回数据）
     * @param executeCall       处理的异步内容
     * @param resultCall        返回处理的内容
     * @param <T>               数据源
     * @return                  post结果
    </T> */
    private fun <T> postExecuteAsync(executeCall: Consumer<Consumer<T>>, resultCall: Consumer<T>): Boolean {
        return postExecuteAsync( Runnable {
            executeCall.accept( Consumer { post { resultCall.accept( it ) } } )
        })
    }

    private fun postExecuteAsync(executeCall: Runnable): Boolean {
        get().execute( executeCall )
        return true
    }
}